#include "adc.h"
#include <string.h>
#include "flash.h"
uint8_t pen_gears = 10;//档位
uint16_t ADC_ResultBuff[6] = {0};// 用于存放 6 路采样结果
uint16_t BAT_ADC_ResultBuff[6] = {0};// 存放电池adc数据
uint16_t gAdcResult;
//校准变量
uint16_t adc_ref[2] = {0x0f,0x0f};
uint16_t adc_ref_cnt = 0;
uint16_t adc_ref_buf[100];
void adc_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    __RCC_GPIOA_CLK_ENABLE();
    // 蜂鸣器
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pins = GPIO_PIN_0 | GPIO_PIN_1;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
}
void adc_dma_config(void)
{
    DMA_InitTypeDef DMA_InitStruct = {0};
    __RCC_DMA_CLK_ENABLE();
    DMA_InitStruct.DMA_DstAddress = (uint32_t)&ADC_ResultBuff;      // 目标地址
    DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Increase;            // 目标地址递增
    DMA_InitStruct.DMA_Mode = DMA_MODE_BULK;                        // BULK 传输模式
    DMA_InitStruct.DMA_SrcAddress = (uint32_t)&CW_ADC->RESULT0;     // 源地址： ADC 的结果寄存器
    DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Fix;                 // 源地址固定
    DMA_InitStruct.DMA_TransferCnt = 0x6;                           // DMA 传输次数
    DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_16BIT;    // 数据位宽 16bit
    DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_TRANSCOMPLETE; // ADC 转换完成硬触发
    DMA_InitStruct.TrigMode = DMA_HardTrig;                         // 硬触发模式
    DMA_Init(CW_DMACHANNEL1, &DMA_InitStruct);
    DMA_Cmd(CW_DMACHANNEL1, ENABLE);

    DMA_InitStruct.DMA_DstAddress = (uint32_t)BAT_ADC_ResultBuff;   // 目标地址
    DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Increase;            // 目标地址递增
    DMA_InitStruct.DMA_Mode = DMA_MODE_BULK;                        // BULK 传输模式
    DMA_InitStruct.DMA_SrcAddress = (uint32_t)&CW_ADC->RESULT1;     // 源地址
    DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Fix;                 // 源地址固定
    DMA_InitStruct.DMA_TransferCnt = 0x6;                           // DMA 传输次数
    DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_16BIT;    // 数据位宽 16bit
    DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_TRANSCOMPLETE; // ADC 转换完成硬触发
    DMA_InitStruct.TrigMode = DMA_HardTrig;                         // 硬触发模式
    DMA_Init(CW_DMACHANNEL2, &DMA_InitStruct);
    DMA_Cmd(CW_DMACHANNEL2, ENABLE);
}
void adc_config(void)
{
    ADC_InitTypeDef ADC_InitStructure = {0};
    ADC_SerialChTypeDef ADC_SerialChStructure = {0};

    __RCC_ADC_CLK_ENABLE();
    ADC_InitStructure.ADC_AccEn = ADC_AccDisable;         // ADC 累加功能不开启
    ADC_InitStructure.ADC_Align = ADC_AlignRight;         // 采样结果右对齐，即结果存于 bit11~bit0
    ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div32;         // ADC 的 采 样 时 钟 为 PCLK 的 32 分 频， 即ADCCLK=2MHz
    ADC_InitStructure.ADC_DMAEn = ADC_DmaEnable;          // ADC 转换完成触发 DMA
    ADC_InitStructure.ADC_InBufEn = ADC_BufDisable;       // 高速采样，ADC 内部电压跟随器不使能
    ADC_InitStructure.ADC_OpMode = ADC_SingleChOneMode;   // 单次单通道采样模式
    ADC_InitStructure.ADC_SampleTime = ADC_SampTime10Clk; // 设置为 10 个采样周期，须根据实际况调整
    ADC_InitStructure.ADC_TsEn = ADC_TsDisable;           // 内部温度传感器禁止
    ADC_InitStructure.ADC_VrefSel = ADC_Vref_BGR2p5;      // 采样参考电压选择为 2.5v

    ADC_SerialChStructure.ADC_Sqr0Chmux = ADC_SqrCh0;
    ADC_SerialChStructure.ADC_Sqr1Chmux = ADC_SqrCh1;
    ADC_SerialChStructure.ADC_SqrEns = ADC_SqrEns01;
    ADC_SerialChStructure.ADC_InitStruct = ADC_InitStructure;

    /* 序列通道连续采样模式 */
    ADC_SerialChContinuousModeCfg(&ADC_SerialChStructure);

    adc_dma_config();
    ADC_Enable();// 启用 ADC
    ADC_SoftwareStartConvCmd(ENABLE);
}
void wait_dma_complete(void)
{
    // 等待DMA传输完成
    if (DMA_GetITStatus(DMA_IT_TC1) == SET)
    {
        DMA_ClearITPendingBit(DMA_IT_TC1|DMA_IT_TC2);
        adc_dma_config();
    }
}
#define AVER_N 6 // 样本容量
float dynamic_mean(uint16_t *num_value, uint16_t value, uint16_t *lenght)
{
    uint16_t len = *lenght;
    uint32_t sum = 0;

    num_value[len++] = value;

    if (len == AVER_N)
        len = 0;

    for (uint8_t w = 0; w < AVER_N; w++)
        sum += num_value[w];
    *lenght = len;
    return (sum / AVER_N);
}
uint16_t bat_cahe[6] = {0};
uint16_t pen_cahe[6] = {0};
uint16_t len_cahe[2] = {0};
uint16_t get_bat_val(void)
{
    uint32_t sum = 0;
    uint16_t bat_val;
    uint32_t len = sizeof(BAT_ADC_ResultBuff) / 2;
    uint16_t max = 0;
    uint16_t min = 0xffff;
    int i;
    for ( i = 0; i < len; i++)
    {
        sum += BAT_ADC_ResultBuff[i];
        if(BAT_ADC_ResultBuff[i] > max)
        {
            max = BAT_ADC_ResultBuff[i];
        }
        if(BAT_ADC_ResultBuff[i] < min)
        {
            min = BAT_ADC_ResultBuff[i];
        }
    }
    sum -= max + min;
    sum = sum / (len - 2);
    sum = dynamic_mean(bat_cahe,sum,len_cahe);
    // sum -= 30;
    bat_val = sum * 2500 * 2 /4095;
    return bat_val;
}
uint16_t pen_volt(void)
{
    uint32_t sum = 0;
    uint16_t val;
    uint32_t len = sizeof(ADC_ResultBuff) / 2;
    uint16_t max = 0;
    uint16_t min = 0xffff;
    int i;
    for ( i = 0; i < len; i++)
    {
        sum += ADC_ResultBuff[i];
        if(ADC_ResultBuff[i] > max)
        {
            max = ADC_ResultBuff[i];
        }
        if(ADC_ResultBuff[i] < min)
        {
            min = ADC_ResultBuff[i];
        }
    }
    sum -= max + min;
    sum = sum / (len - 2);

    val = sum * 2500 / 4095;
    return val;
}
uint16_t get_pen_val(void)
{
    uint16_t val;
    val = dynamic_mean(pen_cahe, pen_volt(), &len_cahe[1]);
    // val = pen_volt();
    if (pen_gears == 1)
    {
        val = val > adc_ref[0] ? (val - adc_ref[0]) : 0;
    }
    else
    {
        val = val > adc_ref[1] ? (val - adc_ref[1]) : 0;
    }
    return val * pen_gears;
}
void clear_adc_ref_cnt(void)
{
    adc_ref_cnt = 0;
}
uint8_t adc_soft_Calibration(uint8_t multiple)
{
    uint32_t sum = 0;
    int i;
    adc_ref_buf[adc_ref_cnt++] = pen_volt();
    while (DMA_GetITStatus(DMA_IT_TC2) == RESET)
    {
    };
    DMA_ClearITPendingBit(DMA_IT_TC1 | DMA_IT_TC2);
    adc_dma_config();

    if (adc_ref_cnt >= 100)
    {
        for (i = 0; i < 100; i++)
        {
            sum += adc_ref_buf[i];
        }
        sum = sum / 100;
        if (multiple == 1)
        {
            adc_ref[0] = sum;
        }
        else
        {
            adc_ref[1] = sum;
        }
        return 1; // 校准完成
    }
    return 0;
}
void clear_pen_cahe(void)
{
    memset(pen_cahe,0,6);
}
void save_adc_ref_val(void)
{
    flash_erase();
    flash_write(adc_ref,2);
}
void read_adc_ref_val(void)
{
    uint16_t buf[2];
    flash_read(buf,2);
    if((buf[0] != 0xff) && (buf[1] != 0xff))
    {
        memcpy(adc_ref,buf,2);
    }
}   
